# Copyright 2021 Tianmian Tech. All Rights Reserved.
# 
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 
#     http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import json
import multiprocessing
import os
from ctypes import *

from common.python.common import consts
from common.python.common.exception.custom_exception import FCCommonError
from common.python.utils import log_utils, conf_utils, file_utils

LOGGER = log_utils.get_logger()


class FCCaller(object):
    """
        Function caller
    """

    SERVICE_NAME = conf_utils.get_comm_config(consts.COMM_CONF_KEY_FC_SERVICE_NAME, 'wefe-fc')
    FUNCTION_NAME = 'index'

    def __init__(self, service_name=SERVICE_NAME, init_client=True):
        self._end_point = conf_utils.get_comm_config(consts.COMM_CONF_KEY_FC_END_POINT)
        self._access_key_id = conf_utils.get_comm_config(consts.COMM_CONF_KEY_FC_ACCESS_KEY_ID)
        self._access_key_secret = conf_utils.get_comm_config(consts.COMM_CONF_KEY_FC_KEY_SECRET)
        self._qualifier = conf_utils.get_comm_config(consts.COMM_CONF_KEY_FC_QUALIFIER)

        self._service_name = service_name
        self.max_processes = multiprocessing.cpu_count()

    def call_fc_by_go(self, input_param: dict, function_name='index'):
        """
        Call function through golang

        Parameters
        ----------
        input_param: Generated by method "_get_fc_input_param" of fc_source.py
        function_name

        Returns
        -------

        """
        go_util = CDLL(os.path.join(file_utils.get_project_base_directory(),
                                    'common/python/calculation/fc/go/pkg/utils.so'))
        go_util.callFC.restype = c_char_p
        fc_name = input_param.get("fc_name")

        res = go_util.callFC(c_char_p(json.dumps(input_param).encode('utf-8')),
                             c_char_p(self._end_point.encode('utf-8')),
                             c_char_p(self._access_key_id.encode('utf-8')),
                             c_char_p(self._access_key_secret.encode('utf-8')),
                             c_char_p(self._service_name.encode('utf-8')),
                             c_char_p(function_name.encode('utf-8')),
                             c_char_p(self._qualifier.encode('utf-8')))

        return self.check_fc_result([json.loads(res)], fc_name, input_param.get("execution_name"))

    def check_fc_result(self, fc_result, fc_name, execution_name=None):
        """
        Check the results of the function execution

        Parameters
        ----------
        fc_result: eg. [['{"code": 100, "data": null}'], ['{"code": 100, "data": null}']]
        fc_name: function name
        execution_name: function execution flag

        Returns
        -------

        """
        check = True
        for item_result_list in fc_result:
            for item_result in item_result_list:
                LOGGER.debug(f'fc_result:{item_result}, execution_name:{execution_name}')
                item_result_dict = json.loads(item_result)
                if 'code' in item_result_dict:
                    if item_result_dict['code'] != 100:
                        msg = None
                        req_id = None
                        if 'message' in item_result_dict:
                            msg = item_result_dict['message']
                        if 'req_id' in item_result_dict:
                            req_id = item_result_dict['req_id']
                        raise FCCommonError(message=f'函数执行异常:{msg}', fc_name=fc_name, req_id=req_id)
                else:
                    raise FCCommonError(message='函数执行异常，未正常响应')
        return check
